package com.danco.training.zaneuskaya.service.impl;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.danco.training.zaneuskaya.annotation.ConfigProperty;
import com.danco.training.zaneuskaya.annotation.ConfigPropertyAnalizer;
import com.danco.training.zaneuskaya.annotation.Type;
import com.danco.training.zaneuskaya.api.BookService;
import com.danco.training.zaneuskaya.connection.DBConnection;
import com.danco.training.zaneuskaya.connection.dao.BookDao;
import com.danco.training.zaneuskaya.connection.dao.ClaimDao;
import com.danco.training.zaneuskaya.connection.dao.OrderDao;
import com.danco.training.zaneuskaya.connection.dao.impl.BookDaoImpl;
import com.danco.training.zaneuskaya.connection.dao.impl.ClaimDaoImpl;
import com.danco.training.zaneuskaya.connection.dao.impl.OrderDaoImpl;
import com.danco.training.zaneuskaya.cswworker.CSVReader;
import com.danco.training.zaneuskaya.cswworker.CSVSaver;
import com.danco.training.zaneuskaya.cswworker.Separator;
import com.danco.training.zaneuskaya.domain.Book;
import com.danco.training.zaneuskaya.domain.Claim;
import com.danco.training.zaneuskaya.domain.Order;

public class BookServiceImpl implements BookService {

	@ConfigProperty(configName = { "test.properties" }, propertyName = "months", type = Type.INTEGER)
	public static int MONTH_NUMBER = 0;

	@ConfigProperty(configName = { "bookshop.properties" }, propertyName = "setclaim", type = Type.BOOLEAN)
	public static boolean EXECUTE_CLAIM = false;

	public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(
			"yyyy.MM.dd");

	private BookDao bookDao = new BookDaoImpl();
	private ClaimDao claimDao = new ClaimDaoImpl();
	private OrderDao orderDao = new OrderDaoImpl();

	private static final Logger logger = Logger
			.getLogger(BookServiceImpl.class);

	private static BookServiceImpl bookStorageSeviceImplInstance;
	private DBConnection driverManagerLoader = DBConnection
			.getDBConnectionInstance();

	public BookServiceImpl() { // public - client send message with className -> reflection -> newInstance()
		ConfigPropertyAnalizer.configPropertyAnalizer(this);
		

	}

	public Book getById(Integer id) {
		Book book = null;
		try (Connection connection = driverManagerLoader.createConnection();) {
			book = bookDao.read(connection, id);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return book;
	}

	public List<Book> getList() {
		List<Book> books = new ArrayList<Book>();
		logger.trace("Book list");
		try (Connection connection = driverManagerLoader.createConnection();) {
			books.addAll(bookDao.readAll(connection));
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return books;
	}

	public List<Book> getSomeMonthsUnsoldBooks() {
		List<Book> res = new ArrayList<Book>();
		try (Connection connection = driverManagerLoader.createConnection();) {

			res = bookDao.readSomeMonthsUnsoldBooks(connection, MONTH_NUMBER);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		logger.trace("MONTH_NUMBER " + " months unsold books are founded");
		return res;

	}

	public List<Book> getBooksSortedByAlphabet() {
		List<Book> list = null ;
		try (Connection connection = driverManagerLoader.createConnection();) {
			list = bookDao.readBooksSortedByAlphabet(connection);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return list;
	}

	public List<Book> getBooksSortedByPublicationDate() {
		List<Book> list = null ;
		try (Connection connection = driverManagerLoader.createConnection();) {
			list = bookDao.readBooksSortedByPublicationDate(connection);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return list;
	}

	public List<Book> getBooksSortedByPrice() {
		List<Book> list = null;
		try (Connection connection = driverManagerLoader.createConnection();) {
			list = bookDao.readBooksSortedByPrice(connection);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return list;

	}

	public List<Book> getBooksSortedByAvailability() {

		List<Book> list = new ArrayList<Book>();
		try (Connection connection = driverManagerLoader.createConnection();) {
			list = bookDao.readBooksSortedByAvailability(connection);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return list;
	}

	public List<Book> getUnsoldBooksSortedByReceiptDate() {

		List<Book> list = new ArrayList<Book>();
		try (Connection connection = driverManagerLoader.createConnection();) {
			list = bookDao.readUnsoldBooksSortedByReceiptDate(connection,
					MONTH_NUMBER);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return list;
	}

	public List<Book> getUnsoldBooksSortedByPrice() {
		List<Book> list = new ArrayList<Book>();
		try (Connection connection = driverManagerLoader.createConnection();) {
			list = bookDao.readUnsoldBooksSortedByPrice(connection, MONTH_NUMBER);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return list;

	}

	public List<Book> getAvailableBooks() {
		List<Book> list = new ArrayList<Book>();
		try (Connection connection = driverManagerLoader.createConnection();) {
			list = bookDao.readAvailableBooks(connection);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return list;

	}

	public List<Book> getNotAvailableBooks() {
		List<Book> list = new ArrayList<Book>();
		try (Connection connection = driverManagerLoader.createConnection();) {
			list = bookDao.readNotAvailableBooks(connection);
		} catch (SQLException e) {
			logger.error(e.getMessage(), e);
		}
		return list;
	}

	public void addEntity(Book book) {
		Connection connection = null;
		try {
			connection = driverManagerLoader.createConnection();
			
			bookDao.create(connection, book);
			
		}

		catch (SQLException e) {

			
			logger.error(e.getMessage(), e);
		} 

	}

	public void removeEntityById(Integer id) {
		Connection connection = null;
		try {
			connection = driverManagerLoader.createConnection();

			connection.setAutoCommit(false);
			Book book = bookDao.read(connection, id);
			List<Claim> claims = claimDao.findClaimByBook(connection, book);
			if (claims != null) {
				for (Claim c : claims) {
					claimDao.delete(connection, c);
				}
			}
			List <Order> orders = orderDao.findOrderByBook(connection, book);
			if (orders != null) {
				for (Order order : orders) {
					orderDao.removeBookOrder(connection, order, book);
					
				}
			}
			bookDao.deleteById(connection, id);

			connection.commit();
			connection.setAutoCommit(true);

		} catch (SQLException e) {
try {
	connection.rollback();
} catch (SQLException e1) {
	logger.error(e1.getMessage(), e1);
}
			logger.error(e.getMessage(), e);
		}
	}

	public void saveEntityListToFile(String file) {
		ArrayList<String> res = new ArrayList<String>();
		try (Connection connection = driverManagerLoader.createConnection();) {
			for (Book b : bookDao.readAll(connection)) {
				res.add(entityDetails(b));
			}
		} catch (SQLException e1) {
			logger.error(e1.getMessage(), e1);
		}
		try {
			CSVSaver.saveListToFile(file, res);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
	}

	@SuppressWarnings("deprecation")
	public List<Book> readEntityList(String file) {
		ArrayList<Book> res = new ArrayList<Book>();

		Date date = null;

		for (int i = 0; i < CSVReader.readFile(file).length; i++) {
			String book[] = CSVReader.readFile(file)[i]
					.split(Separator.SEPARATOR.getS());
			try {

				date = DATE_FORMAT.parse(book[3]);
			} catch (ParseException e) {
				logger.error(e.getMessage(), e);
			}
			Book b = new Book(Integer.parseInt(book[0]), book[1], book[2], date);
			res.add(b);

		}
		return res;
	}

	public static BookServiceImpl getBookStorageSeviceImplInstance() {

		if (bookStorageSeviceImplInstance == null) {
			bookStorageSeviceImplInstance = new BookServiceImpl();

		}
		return bookStorageSeviceImplInstance;
	}

	public String entityDetails(Book t) {

		StringBuffer str = new StringBuffer();

		str.append(t.getId());
		str.append(Separator.SEPARATOR.getS());
		str.append(t.getTitle());
		str.append(Separator.SEPARATOR.getS());
		str.append(t.getAuthor());
		str.append(Separator.SEPARATOR.getS());
		str.append(DATE_FORMAT.format(t.getPublicationDate()));

		return str.toString();
	}

	@Override
	public void updateEntity(Book e) {
		Connection connection = null;
		try {
			connection = driverManagerLoader.createConnection(); 
			connection.setAutoCommit(false);
			bookDao.update(connection, e);
			List<Claim> claims = claimDao.findClaimByBook(connection, e);
			if (!claims.isEmpty()){
			for (Claim claim : claims) {
				if (claim.getClaimAmount() <= e.getQuantity()) {
					claimDao.executeClaim(connection, claim);
				}
			}
			
			}
			
			connection.commit();
			connection.setAutoCommit(true);
		} catch (SQLException e1) {
			try {
				connection.rollback();
				
			} catch (SQLException e2) {
				logger.error(e2.getMessage(), e2);
			}

			logger.error(e1.getMessage(), e1);
		}
		
	}

}
